﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using System.Collections.ObjectModel;
namespace ERF
{
    /// <summary>
    /// Represents a tree of GameObject nodes.
    /// </summary>
    public class SceneGraph : DrawableGameComponent
    {
        private SynchronizedCollection<GameObject> items;
        private Matrix world = Matrix.Identity;
        
        private Vector3 position = Vector3.Zero;
        private Vector3 scale = Vector3.One;
        private Vector3 rotation = Vector3.Zero;
        private ERFGame game;

        public event EventHandler UpdateEnd;

        /// <summary>
        /// Gets or sets the position of the entire scene.
        /// </summary>
        public Vector3 Position
        {
            get { return this.position; }
            set { this.position = value; }
        }

        /// <summary>
        ///  Gets or sets the scale of the entire scene.
        /// </summary>
        public Vector3 Scale
        {
            get { return this.scale; }
            set { this.scale = value; }
        }

        /// <summary>
        /// Gets or sets the rotation of the entire scene.
        /// </summary>
        public Vector3 Rotation
        {
            get { return this.rotation; }
            set { this.rotation = value; }
        }

        /// <summary>
        /// Gets the game that this SceneGraph belongs to.
        /// </summary>
        public ERF.ERFGame ErfGame
        {
            get { return this.game; }
            set { this.game = value; }
        }

        /// <summary>
        /// Gets the items in the SceneGraph.
        /// </summary>
        public SynchronizedCollection<GameObject> Items
        {
            get { return this.items; }
        }

        /// <summary>
        /// Creates a new instance of SceneGraph.
        /// </summary>
        /// <param name="game">The game this instance belongs to.</param>
        public SceneGraph(ERFGame game)
            : base(game) {
            this.game = game;
            this.items = new SynchronizedCollection<GameObject>();
        }

        public override void Update(GameTime gameTime)
        {
            this.UpdateWorld();
            foreach (GameObject item in items)
            {
                if(item.Enabled)
                    item.Update(gameTime, ref this.world);
            }

            this.items.ApplyChanges();

            if (this.UpdateEnd != null)
                this.UpdateEnd(this, EventArgs.Empty);

            base.Update(gameTime);
        }

        public override void Draw(GameTime gameTime)
        {
            foreach (GameObject item in items)
            {
                if (item.Visible) {
                    item.DrawSolid(gameTime);
                    item.DrawTransparent(gameTime);
                }
                item.DrawChildren(gameTime);
            }
            base.Draw(gameTime);
        }

        /// <summary>
        /// Updates the world matrix.
        /// </summary>
        private void UpdateWorld() {
            Matrix rotationX, rotationY, rotationZ, translation, scale;
            Matrix.CreateRotationX(this.rotation.X, out rotationX);
            Matrix.CreateRotationY(this.rotation.Y, out rotationY);
            Matrix.CreateRotationZ(this.rotation.Z, out rotationZ);
            Matrix.CreateScale(ref this.scale, out scale);
            Matrix.CreateTranslation(ref this.position, out translation);
            this.world = scale * rotationX * rotationY * rotationZ * translation;
        }
    }
}
